#include "ml307r.h"
#include "cJSON.h"

#define ml307r_delay_ms osDelay
#define ml307r_send_data Uart2_SendStr
#define ml307r_log_print debug_printf

#define WIFI_AGREEMENT "TCP"                                                                                       // 连接协议
#define SEVER_URL_IP "test123.fucku.top"                                                                           // 服务器IP
#define URL_TARGET_PORT "80"                                                                                       // 服务器端口
#define CONNECT_SERVER_INFO "AT+MIPOPEN=0,\"" WIFI_AGREEMENT "\",\"" SEVER_URL_IP "\"," URL_TARGET_PORT ",,1\r\n " // AT指令：连接服务器
#define DATA_TRANSPARTENT_MODE_INFO "AT+MIPMODE=0,1\r\n"                                                           // AT指令：透传模式

ML307R_TypeDef ML307R_Status = {0, 0, 0, 0};
ML307R_Data ML307R_Data_Info = {0.0, {0}, 0.0, {0}}; // 用于存储电费数据

const char building_map[16][6] = {"南1", "南2", "南3", "南4", "南5", "南6", "南7", "南8", "中1A", "中1B", "中1C", "中1D", "东20", "东21", "东22", "东23"};
static building_info_t building_info = {NO_SELECT, DEFAULT_BUILDING, DEFAULT_FLOOR, DEFAULT_ROOM}; // 楼号映射表                                                                                                        // 楼层对应房间号 如704 则填4

static void Uart2_SendStr(char *str)
{
    if (str == NULL)
        return; // 确保指针不为空

    // 计算字符串长度，不包括结尾的'\0'
    uint16_t len = strlen(str);
    // 发送数据
    HAL_UART_Transmit_DMA(&huart2, (uint8_t *)str, len);
    // HAL_UART_Transmit(&huart2, (uint8_t *)str, len, HAL_MAX_DELAY);
}

static void ml307r_clear_buffer(void)
{
    memset(ML307R_RX.RxBuffer, 0, RX_BUFFER_SIZE);
    ML307R_RX.RxDataCnt = 0;
    // xQueueReset(ml307r_RX_QueueHandle);
}
/**
 * @brief 用来将字符转为对应的 URL 编码形式
 *
 * @param str   原始字符串
 * @param encoded_str 编码后的字符串
 */

static void url_encode(const char *str, char *encoded_str)
{
    int i, j = 0;
    unsigned char c;

    for (i = 0; str[i] != '\0'; i++)
    {
        c = (unsigned char)str[i];

        // 如果是普通字符，不需要编码
        if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~')
        {
            encoded_str[j++] = c;
        }
        else
        {
            // 将字符转换为 %XX 形式
            sprintf(encoded_str + j, "%%%02X", c);
            j += 3; // 每个字符占3个位置，例如 %E5
        }
    }
    encoded_str[j] = '\0'; // 结束符
}

static uint8_t ml307r_send_command(char *cmd, char *res, uint8_t sendCount, uint16_t delay_xms, uint8_t printf_enable)
{
    if (printf_enable == W_ENABLE)
        ml307r_log_print("%s", cmd); // 这里可以打印每次发送的指令
    UART_RxTypeDef *ml307r_res = NULL;
    while (sendCount--)
    {
        ml307r_send_data(cmd); // AT指令发送
        ml307r_delay_ms(delay_xms);
        while (osMessageQueueGet(ml307r_RX_QueueHandle, &ml307r_res, NULL, delay_xms) == osOK)
        {
            if (strstr((const char *)ml307r_res->RxBuffer, res) != NULL)
            {
                ml307r_log_print("%s\r\n", res);
                ml307r_clear_buffer();
                return W_OK; // 返回0-成功
            }
            // ml307r_log_print("error %s\r\n", ml307r_res->RxBuffer); // 没有找到关键字
            // ml307r_clear_buffer();
        }
        // ml307r_delay_ms(500);
    }
    return W_ERROR; // 返回1-失败
}

int ml307r_init(void)
{
    OLED_Printf(22, 16, OLED_6X8, "init ml307r...");
    OLED_Printf(22, 32, OLED_6X8, "version:RTOS");
    OLED_Update();
    ml307r_send_data("+++");
    ml307r_delay_ms(100);
    if (ml307r_send_command("AT+RESET\r\n", "OK", 3, 1500, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT+REST error\r\n");
        ML307R_Status.error_code |= (1 << 0);
        ML307R_Status.init_flag = 1;
    }
    ml307r_delay_ms(2000);
    if (ml307r_send_command("AT\r\n", "OK", 3, 100, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT error\r\n");
        ML307R_Status.error_code |= (1 << 0);
        ML307R_Status.init_flag = 1;
    }
    ml307r_delay_ms(100);
    if (ml307r_send_command("ATE0\r\n", "OK", 3, 100, W_ENABLE) != W_OK)
    {
        ml307r_log_print("ATE0 error\r\n");
        ML307R_Status.error_code |= (1 << 1);
        ML307R_Status.init_flag = 1;
    }
    ml307r_delay_ms(100);
    if (ml307r_send_command("AT+CPIN?\r\n", "OK", 3, 100, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT+CPIN? error\r\n");
        ML307R_Status.error_code |= (1 << 2);
        ML307R_Status.init_flag = 1;
    }
    ml307r_delay_ms(100);
    if (ml307r_send_command(CONNECT_SERVER_INFO, "CONNECT", 3, 4000, W_ENABLE) != W_OK)
    {
        ml307r_log_print("AT+MIPOPEN error\r\n");
        ML307R_Status.error_code |= (1 << 3);
        ML307R_Status.init_flag = 1;
    }
    // ml307r_delay_ms(2000);
    return ML307R_Status.init_flag; // 返回0-成功
}

/**
 * @brief 通过cjson库获取电费数据
 * @note json数据格式如下
 * {
  "building": "南5",
  "current": {
    "remain": 56.15,
    "unit": "kWh",
    "update_time": "2025-08-10 20:25:00"
  },
  "records": [
    {
      "time": "2025-08-09 23:33",
      "usage": "12.85"
    }
  ],
  "room": "南5#704",
  "time": "2025-08-10 20:27:08"
}
 * @return uint8_t 0成功 1失败
 */
static uint8_t get_electricity_data(void)
{
    UART_RxTypeDef *ml307r_res = NULL;

    // 队列获取数据
    while (osMessageQueueGet(ml307r_RX_QueueHandle, &ml307r_res, NULL, 4000) == osOK)
    {
        char *json_data = strchr((char *)ml307r_res->RxBuffer, '{'); // 查找 JSON 数据的起始位置
        if (json_data != NULL)
        {
            cJSON *json_obj = cJSON_Parse(json_data);
            if (json_obj == NULL)
            {
                const char *error_ptr = cJSON_GetErrorPtr();
                if (error_ptr != NULL)
                {
                    ml307r_log_print("Error before: %s\r\n", error_ptr);
                }
                cJSON_Delete(json_obj); // 释放内存
                ml307r_log_print("json obj is NULL\r\n");
                return 1; // 解析失败
            }

            // 解析 JSON 数据
            cJSON *current = cJSON_GetObjectItem(json_obj, "current");
            if (current != NULL)
            {
                cJSON *remain = cJSON_GetObjectItem(current, "remain");
                if (remain != NULL)
                {
                    ML307R_Data_Info.remain = remain->valuedouble;
                    ml307r_log_print("remain: %.2f\r\n", ML307R_Data_Info.remain);
                }
                cJSON *update_time = cJSON_GetObjectItem(current, "update_time");
                if (update_time != NULL)
                {
                    sprintf(ML307R_Data_Info.update_time, "%s", update_time->valuestring);
                    ml307r_log_print("update_time: %s\r\n", ML307R_Data_Info.update_time);
                }
            }

            // 解析电量记录
            cJSON *records = cJSON_GetObjectItem(json_obj, "records");
            if (records != NULL)
            {
                cJSON *record = cJSON_GetArrayItem(records, 0);
                if (record != NULL)
                {
                    cJSON *time = cJSON_GetObjectItem(record, "time");
                    if (time != NULL)
                    {
                        sprintf(ML307R_Data_Info.time, "%s", time->valuestring);
                        ml307r_log_print("time: %s\r\n", ML307R_Data_Info.time);
                    }
                    cJSON *usage = cJSON_GetObjectItem(record, "usage");
                    if (usage != NULL)
                    {
                        ML307R_Data_Info.usage = atof(usage->valuestring);
                        ml307r_log_print("usageddd: %.2f\r\n", ML307R_Data_Info.usage);
                    }
                }
            }
            /*解析成功*/
            cJSON_Delete(json_obj); // 释放内存
            ml307r_clear_buffer();  // 清空接收缓冲区
            return 0;               // 解析成功
        }
        /*在接收缓冲区中得不到json数据*/
        else
        {
            ml307r_log_print("json_data is NULL\r\n");
            ml307r_clear_buffer();
            return 1;
        }
    }
    /*4s内获取不到队列的数据*/
    ml307r_log_print("no data\r\n");
    ml307r_clear_buffer();
    return 1;
}

void ml307r_get_electricity(void *arg)
{
    building_info_t *data = &building_info;
    char temp[10] = {0};
    char get_command[256] = {0}; // 用于存储GET请求命令
    uint16_t room_id = 0;
    int result = ml307r_init();
    OLED_Clear();
    OLED_Update();
    if (result == 0)
    {
        xSemaphoreGive(ml307r_init_finish_sem);
        ml307r_log_print("ml307r_init success\r\n");
        OLED_Printf(10, 16, OLED_6X8, "init ml307r success");
        OLED_UpdateArea(0, 16, 128, 16);
        xQueueOverwrite(building_data_QueueHandle, &data);
    }
    else
    {
        ml307r_log_print("ml307r_init fail\r\n");
        OLED_Printf(13, 16, OLED_6X8, "init ml307r error");
        OLED_UpdateArea(0, 16, 128, 16);
        ml307r_init();
    }
    // OLED_ClearArea(0, 16, 128, 32);
    // OLED_UpdateArea(0, 16, 128, 32);
    EventBits_t evb;
    BaseType_t need_to_retry = pdFALSE; // 标记是否需要立即重试
    while (1)
    {
        evb = xEventGroupWaitBits(status_event_group, SYSTEM_SLEEP_EVENT | BUILDING_SET_EVENT | GET_ELE_JSON_EVENT, pdTRUE, pdFALSE, 500);
        /*既不处于休眠模式也不处于设置模式*/
        if (!(evb & SYSTEM_SLEEP_EVENT) && !(evb & BUILDING_SET_EVENT))
        {
            OLED_ShowChinese(16, 16, "获取电费：");
            OLED_UpdateArea(16, 16, 128, 16);
            xQueuePeek(building_data_QueueHandle, &data, 0);
            ml307r_clear_buffer();
            room_id = data->floor_num_temp * 100 + data->room_num_temp;
            url_encode(building_map[data->map_num_temp], temp); // 编码楼号
            sprintf(get_command, "GET /electricity?building=%s&room=%d&limit=1 HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n\r\n", temp, room_id, SEVER_URL_IP);
            ml307r_log_print("%s", get_command);
            ml307r_send_data(get_command);
            int res = get_electricity_data();
            if (res == 0)
            {
                if (!(evb & GET_ELE_JSON_EVENT))
                {
                    OLED_ShowChinese(16 + 80, 16, "成功");
                    OLED_ClearArea(30, 32, 128, 16);
                    OLED_UpdateArea(16, 16, 128, 32);
                    vTaskDelay(1000); // 先显示1秒再清除
                    OLED_ClearArea(0, 16, 128, 32);
                    OLED_UpdateArea(0, 16, 128, 32);
                }
                else
                {
                    OLED_Clear();
                    OLED_Update();
                }
                xEventGroupSetBits(status_event_group, GET_ELE_JSON_EVENT);
                ml307r_log_print("get electricity data success\r\n");
                need_to_retry = pdFALSE; // 重置标志位
            }
            /*其他错误情况获取不到数据 如json_data is NULL 或 no data*/
            else
            {
                /*清除获取到电费的事件组 标记为获取失败事件组 */
                xEventGroupClearBits(status_event_group, GET_ELE_JSON_EVENT);
                OLED_ShowChinese(16 + 80, 16, "失败");
                OLED_ShowChinese(30, 32, "正在重试");
                OLED_UpdateArea(16, 16, 128, 32);
                need_to_retry = pdTRUE; // 需要立即重试
                vTaskDelay(500);
            }
            if (!need_to_retry)
                ulTaskNotifyTake(pdTRUE, 300000); // 等待任务通知，最长等待时间为5分钟
        }
    }
}

float ml307r_get_remain(void)
{
    return ML307R_Data_Info.remain;
}
float ml307r_get_usage(void)
{
    return ML307R_Data_Info.usage;
}
char *ml307r_get_update_time(void)
{
    return ML307R_Data_Info.update_time;
}
char *ml307r_get_time(void)
{
    return ML307R_Data_Info.time;
}

char *get_building_map_index(uint8_t index)
{
    if (index <= EAST_23)
        return (char *)building_map[index];
    else
        return NULL;
}
/**
 * @brief 获取楼栋号（去掉第一个中文字符）
 *
 * @return char*
 */
char *get_building_map_remain_index(uint8_t index)
{
    static char result[8];

    char *map = get_building_map_index(index);

    // 如果map为NULL，返回空字符串而不是NULL
    if (map == NULL)
    {
        result[0] = '\0'; // 清空结果
        return result;
    }

    size_t len = strlen(map);
    if (len <= 3)
    {
        result[0] = '\0'; // 清空结果
        return result;
    }

    // 将map字符串从索引3开始复制到result
    strcpy(result, map + 3);

    return result;
}
